
import { Injectable } from '@angular/core';
import * as gc from 'src/app/global/const';
import { NzSort, NzFilterOpts, NzFilterReference, JsonResult, ZorroOption } from '../global/model';
import { HttpClient } from '@angular/common/http';
import { DatePipe } from '@angular/common';
import { ArrayutilsService } from './arrayutils.service';
import { Observable, of, forkJoin } from 'rxjs';
import { map } from 'rxjs/operators';
import { TableStyle, TableStyleService } from './table-style.service';
import { UUID } from 'angular2-uuid';
import { BreadFieldService } from './bread-field.service';

@Injectable({
  providedIn: 'root'
})
export class SysRolepService {

  //#region 公共属性
  private sortData:NzSort = null;
  private path_pre = 'sysRolep';
  private tableName='sys_rolep';
  filterOpts:{ [fieldName:string]:NzFilterOpts[] } = {};
  filterMultiple:{ [fieldName:string]:boolean } = {};
  filterReference:NzFilterReference = new NzFilterReference();
  tableData:SysRolep[] = [];
  tableDataDisplay:SysRolep[] = [];
  tableStyle:TableStyle[] = [];
  editCache:{ [key:string]:{ edit:boolean,data:SysRolep } };// 编辑时的缓存数据
  enums:{ [key:string]:{label:string,value:string}[] } = {};
  emptyRowCount:number = 6;
  statistics:{ [key:string]:{ label:string,value:number } } = {};
  //#endregion

  //#region 请求URL
  private url = {
    'deleteByPrimaryKey':gc.BACKEND_SERVER_ROOT + '/' + this.path_pre + '/deleteByPrimaryKey',
    'selectByPrimaryKey':gc.BACKEND_SERVER_ROOT + '/' + this.path_pre + '/selectByPrimaryKey',
    'selectAll':gc.BACKEND_SERVER_ROOT + '/' + this.path_pre + '/selectAll',
    'saveOne':gc.BACKEND_SERVER_ROOT + '/' + this.path_pre,
    'insert':gc.BACKEND_SERVER_ROOT + '/' + this.path_pre + '/insert',
    'update':gc.BACKEND_SERVER_ROOT + '/' + this.path_pre + '/update',
    'restoreDeleted':gc.BACKEND_SERVER_ROOT + '/' + this.path_pre + '/restoreDeleted',
    'selectByRoleIid':gc.BACKEND_SERVER_ROOT + '/' + this.path_pre + '/selectByRoleIid',
  }
  //#endregion

  //#region 构造方法 - 依赖注入
  constructor(
    private http:HttpClient,
    private datePipe:DatePipe,
    private arrUtils:ArrayutilsService,
    private tableStyleService:TableStyleService,
    private breadField:BreadFieldService,
  ) { }
  //#endregion

  //#region 查询获取角色拥有的权限
  selectByRoleIid(roleIid:number):Observable<JsonResult>{
    const url = this.url.selectByRoleIid + '/' + roleIid;
    console.log('获取角色权限数据的请求是：' + url);
    return this.http.get<JsonResult>(url);
  }
  //#endregion

  //#region 删除行
  deleteByPrimaryKey(iid:number,rowIndex:number):Observable<JsonResult>{
    const url = this.url.deleteByPrimaryKey + '/' + iid;
    let record = this.tableDataDisplay.filter( item => item.iid === iid )[0];
    if( !record ) return of(JsonResult.getError('显示数据中未能获取到即将被删除的数据！'));
    let uuid:string = record.uuid;
    if( !uuid ) return of(JsonResult.getError('获取被删除数据的uuid失败！'));
    return this.http.delete<JsonResult>(url).pipe(map(
      ( jr:JsonResult ) =>{
        if( jr.code !==1 ) return jr;

        // 是作废模式的话，使用下面一行代码，相反则维持现状
        // this.nullifyRow_front(rowIndex,uuid);
        this.deleteRow_front(uuid);

        this.updateStatistics();
        return jr;
      }
    ));
  }
  //#endregion

  //#region 根据主键查询，加工：设置UUID，日期类型转换
  selectByPrimaryKey(iid:number):Observable<JsonResult>{
    const url = this.url.selectByPrimaryKey + '/' + iid;
    return this.http.get<JsonResult>(url).pipe(map(
      ( jr:JsonResult ) =>{
        if( jr.code !==1 ) return jr;
        let data:SysRolep = jr.data;
        if( data === undefined || data === null ) return jr;
        data.uuid = UUID.UUID();
        jr.data = this.transDate4Display(data);
        return jr;
      }
    ));
  }
  //#endregion

  //#region 查询获取所有数据后做如下操作：
  //1. 遍历数组设置UUID
  //2. 拷贝数组到tableDataDisplay
  selectAll():Observable<JsonResult>{
    return this.http.get<JsonResult>(this.url.selectAll).pipe(map(
      ( jr:JsonResult ) =>{
        if( jr.code !==1 ) return jr;
        let data:SysRolep[] = jr.data;
        if( data === undefined || data === null || data.length<=0 ) return jr;
        
        //1. 遍历数组设置UUID，同时转换日期类型
        data.forEach(ele => {
          ele.uuid = UUID.UUID();
          ele = this.transDate4Display(ele);
        });

        this.tableData = data;

        //3. 拷贝数据到 tableDataDisplay
        this.tableDataDisplay = {...data};

        jr.data = data;
        return jr;
      }

      
    ));
  }
  //#endregion

  //#region 保存一行数据
  saveOne(record:SysRolep):Observable<JsonResult>{
    if( record === undefined || record === null ){
      let jr:JsonResult = new JsonResult();
      jr.code = 777;
      jr.msg = '数据为空，不可保存！';
      return of(jr);
    }
    record = this.transDate4save(record);
    if( record.iid === undefined || record.iid === null || record.iid <=0 )
      return this.insert(record);
    else
      return this.update(record);
  }
  //#endregion
  
  //#region 插入一行数据
  private insert(record:SysRolep):Observable<JsonResult>{
    return this.http.post<JsonResult>(this.url.insert,record).pipe(map((jr:JsonResult) =>{
      if( jr.code !==1 ) return jr;
      let data:SysRolep = jr.data;
      if( data === undefined || data === null ) return jr;
      return jr;
    }));
  }
  //#endregion

  //#region 恢复被删除的数据
  restoreDeleted(iid:number,rowIndex:number):Observable<JsonResult>{
    const url = this.url.restoreDeleted + '/' + iid;
    return this.http.put<JsonResult>(url,null).pipe(map(
      ( res:JsonResult ) =>{
        if( res.code !==1 ) return res;
        this.tableData[rowIndex].state = 1;
        this.tableDataDisplay[rowIndex].state = 1;
        this.tableData = this.tableData.filter( item => 1===1 );
        this.tableDataDisplay = this.tableDataDisplay.filter( item => 1===1 );
        const uuid:string = this.tableData[rowIndex].uuid;
        this.editCache[uuid].data.state = 1;
        this.updateStatistics();
        return res;
      }
    ))
  }
  //#endregion

  //#region 修改一行数据
  private update(record:SysRolep):Observable<JsonResult>{
    console.log('sys-rolep服务中修改请求的URL：' + this.url.update);
    console.log(record);
    return this.http.put<JsonResult>(this.url.update,record).pipe(map((jr:JsonResult) =>{
      if( jr.code !==1 ) return jr;
      let data:SysRolep = jr.data;
      if( data === undefined || data === null ) return jr;
      return jr;
    }))
  }
  //#endregion

  //#region 日期类型转换 - 为保存
  transDate4save(record:SysRolep):SysRolep{
    if( this.tableStyle === undefined || this.tableStyle === null || this.tableStyle.length<=0 ) return record;
    if( record === undefined || record === null ) return null;
    
    let dateTs:TableStyle[] = this.tableStyle.filter( item => item.date_formatter !== undefined && item.date_formatter !==null && item.date_formatter.length>0);
    if( dateTs.length<=0 ) return record;
    dateTs.forEach(ele => {
      if( record[ele.field_name] ){
        let date:Date = new Date(record[ele.field_name]);
        record[ele.field_name] = this.datePipe.transform(date,"yyyy-MM-dd HH:mm:ss");
      }
    });
    return record;
  }
  //#endregion

  //#region 日期类型转换 - 为显示
  transDate4Display(record:SysRolep):SysRolep{
    if( this.tableStyle === undefined || this.tableStyle === null || this.tableStyle.length<=0 ) return record;
    if( record === undefined || record === null ) return null;
    
    let dateTs:TableStyle[] = this.tableStyle.filter( item => item.date_formatter !== undefined && item.date_formatter !==null && item.date_formatter.length>0);
    if( dateTs.length<=0 ) return record;
    dateTs.forEach(ele => {
      let date:Date = new Date(record[ele.field_name]);
      record[ele.field_name] = this.datePipe.transform(date,ele.date_formatter);
    });
    return record;
  }
  //#endregion

  //#region 使用表格数据和样式数据构建用于过滤的下拉选项数组
  buildFilterOpts(td:SysRolep[],ts:TableStyle[]){
    if( !td || !ts ) return;
    for(let i=0;i<ts.length;i++){
      let ele = ts[i];
      let fieldName:string = ele.field_name;
      if( ele.filter === undefined || ele.filter === null || ele.filter.length<=0 || ele.filter ==='input'){
        continue;
      }
        

      let arr:SysRolep[] = this.arrUtils.buildDistArray(td,[ele.field_name]);
      if( arr ){
        let filterOpts:NzFilterOpts[] = [];
        arr.forEach(e1 => {
          let filterOptTextFieldName:string = ts[i].display_field;
          if( filterOptTextFieldName )
            filterOpts.push({text:e1[filterOptTextFieldName],value:e1[fieldName]});
          else
            filterOpts.push({text:e1[fieldName],value:e1[fieldName]});
        });

        this.filterOpts[fieldName] = filterOpts;

        // 设置过滤是否多选
        if( ts[i].filter === 'multiple' )
          this.filterMultiple[ts[i].field_name] = true;
        if( ts[i].filter === 'single' )
          this.filterMultiple[ts[i].field_name] = false;
        
      }else{
        console.log('字段' + ts[i].field_name + '构建过滤用选项数组失败！');
      }
    }
  }
  //#endregion

  //#region 保存排序用参数，调用方法先过滤再排序
  sort(record:NzSort){
    this.sortData = record;
    this.filterGo();
  }
  //#endregion

  //#region 外部调用过滤方法
  filter(opts:string[],fieldName:string){
    this.filterReference = new NzFilterReference();
    this.filterReference.fieldName = fieldName;
    this.filterReference.opts = opts;
    this.filterGo();
  }
  //#endregion

  //#region 执行过滤
  filterGo(){
    let displayData:SysRolep[] = [];
    // 过滤
    displayData = this.tableData.filter(
      ( item:SysRolep ) =>{

        if( this.filterMultiple[this.filterReference.fieldName] === true ){// 多选过滤
          let fieldData:String = new String(item[this.filterReference.fieldName]);
          return this.filterReference.opts.some(
            ( val:string ) => fieldData.indexOf(val) !==-1
          ) ?true:false;
        }

        if( this.filterMultiple[this.filterReference.fieldName] === false ){// 单选过滤
          let fieldData:String = new String(item[this.filterReference.fieldName]);
          let opt:string = <string>(this.filterReference.opts);
          return fieldData == opt;
        }

      }
    )

    if( this.filterReference.opts === null || this.filterReference.opts.length<=0 )
      displayData = this.tableData;
    

    this.tableDataDisplay = displayData;

    // 更新统计数据
    this.updateStatistics();

    // 无须排序
    if( this.sortData === undefined || this.sortData === null )
      return
    
      // 排序
    this.tableData = displayData.sort(
      (a,b) =>
      this.sortData.value === 'ascend'
      ? a[this.sortData.key!] > b[this.sortData.key!]
        ? 1
        : -1
      : b[this.sortData.key!] > a[this.sortData.key!]
      ? 1
      : -1
    );
    
  }
  //#endregion

  //#region 使用 forkJoin 同时获取数据和样式，并且初始化
  // 1. 编辑数据填充UUID，格式化日期类型字段的值
  // 2. 赋值 tableDataDisplay
  // 3. 构建用于过滤的下拉选项数组
  refresh():Observable<JsonResult>{
    const getData$ = this.http.get(this.url.selectAll);
    const getStyle$ = this.tableStyleService.selectByTableName(this.tableName);
    return forkJoin(getData$,getStyle$).pipe(map(
      ( res:any[] ) =>{
        if( !res ) return JsonResult.getError('请求服务器数据时出现异常！');
        let jrData:JsonResult = res[0];
        let jrStyle:JsonResult = res[1];
        if( !jrData || jrData.code !==1 ) return JsonResult.getError('获取数据时出现异常！');
        if( !jrStyle || jrStyle.code !==1 ) return JsonResult.getError('获取数据样式时出现异常！');

        // 成功获取数据和样式后，对数据进行必要的加工同时构建用于过滤的下拉选项数组
        // 1. 数据添加UUID，格式化日期类型
        // 2. 构建用于过滤的下拉选项数组
        jrData.data = this.resolveDataAndStyle(jrData.data,jrStyle.data);
        this.updateStatistics();
        return new JsonResult();
      }
    ))
  }
  //#endregion

  //#region 使用 table_style 表的设置修饰请求来的数据
  // 1. 为数据设置uuid
  // 2. 拷贝数据到tableDataDisplay
  // 3. 初始化编辑用缓存数据
  // 4. 构建过滤用的下拉数据源
  // 5. 构建枚举值
  // 6. 设置列宽、数字0显示为空字符串
  // 7. 最后返回修饰后的数据
  private resolveDataAndStyle(records:SysRolep[],ts:TableStyle[]):SysRolep[]{
    if( !records ) return null;
    if( !ts ) return records;

    let tsDate:TableStyle[] = ts.filter( item => item.date_formatter !== undefined && item.date_formatter !== null && item.date_formatter.length>0 );

    this.tableData = [];
    this.tableDataDisplay = [];
    // 遍历数据行，设置UUID，格式化日期类型字段
    records.forEach(dataRow => {
      dataRow.uuid = UUID.UUID();
      this.tableData.push({...dataRow});
      this.tableDataDisplay.push({...dataRow});
    });

    this.tableDataDisplay = this.tableDataDisplay.filter( item => 1===1 );

    // 给服务内属性赋值
    this.tableStyle = ts;
    this.updateEditCacheWithTableData();

    // 构建用于过滤的下拉选项数组
    this.buildFilterOpts(records,ts);

    // 遍历样式数组，设置列宽，构建枚举值
    ts.forEach(ele => {
      if( ele.data_type === 'number' ){// 数值0显示为空字符串
        this.tableDataDisplay.forEach(eleDD => {
          if( eleDD[ele.field_name] ===0 )
            eleDD[ele.field_name] = null;
        });
      }
      ele.width_percent_str = ele.width_percent + 'px';
      this.buildEnums(ele);// 构建枚举值
    });

    return records;
  }
  //#endregion

  //#region 构建枚举值
  buildEnums(tsRow:TableStyle){
    if( !tsRow ) return
    if( tsRow.ctl_type !=='enum' ) return
    
    let opts:string[] = new String(tsRow.opts).split(',');
    let optsArray:ZorroOption[] = [];
    opts.forEach(ele => {
      optsArray.push({ label:ele,value:ele });
    });
    this.enums[tsRow.field_name] = optsArray;
  }
  //#endregion

  //#region 使用表格数据更新编辑用缓存数据
  updateEditCacheWithTableData(){
    if( !this.tableData ) return
    this.editCache = {};
    this.tableData.forEach(ele => {
      this.editCache[ele.uuid] = { edit:false,data:{...ele} };
    });
  }
  //#endregion

  //#region 从编辑缓存中获取所有处于编辑状态的行构建为数组返回
  getEdited():SysRolep[]{
    let ret:SysRolep[] = [];
    for(let attr in this.editCache){
      if( this.editCache[attr].edit === true ){
        ret.push({...this.editCache[attr].data});
      }
    }

    return ret;
  }
  //#endregion

  //#region 初始化来自基础资料的下拉数据源
  initOpts():Observable<JsonResult>{
    // const cashType$ = this.cashTypeService.selectAll();
    // const cc$ = this.ccService.selectAll();

    // return forkJoin( cashType$,cc$ ).pipe(map(
    //   ( res:any[] ) =>{

    //     if( !res ) JsonResult.getError('初始化下拉数据时出现异常！');
    //     let ddCashType:JsonResult = res[0];
    //     let ddCC:JsonResult = res[1];

    //     this.cashType = ddCashType.data ? ddCashType.data:null;
    //     this.cc = ddCC.data ? ddCC.data:null;

    //     return new JsonResult();
    //   }
    // ))
    return of(new JsonResult);
  }
  //#endregion

  //#region 新增空行
  addEmptyRow(){
    let record:SysRolep = new SysRolep();
    let uuid:string = record.uuid;

    this.setDefaultValue(record);// 设置默认值
    this.addEmptyRowAtHeader(record);

    this.editCache[uuid] = {
      edit:true,data:{...record}
    };
  }
  //#endregion

  //#region 设置默认值
  private setDefaultValue(record:SysRolep){
    if( !this.tableStyle ) return;
    this.tableStyle.forEach(ele => {
      if( ele.default_value ){
        switch(ele.data_type){
          case 'date':
            let val:number = Date.parse(new Date().toString()) + parseInt(ele.default_value);
            record[ele.field_name] = new Date(val);
            break;
          default:
            record[ele.field_name] = ele.default_value;
        }
      }
    });
  }
  //#endregion

  //#region 在数组头上添加空行
  addEmptyRowAtHeader(record:SysRolep){
    this.tableData = this.tableData.filter( item => 1===1 );
    this.tableData.splice(0,0,{...record});

    this.tableDataDisplay = this.tableDataDisplay.filter( item => 1===1 );
    this.tableDataDisplay.splice(0,0,{...record});
  }
  //#endregion

  //#region 在数组尾部添加空行
  addEmptyRowAtFooter(record:SysRolep){
    this.tableData = this.tableData.concat({...record});
    this.tableDataDisplay = this.tableDataDisplay.concat({...record});
  }
  //#endregion

  //#region 保存编辑：新增后的编辑 + 修改的编辑
  saveEdit(rowIndex:number,uuid:string):Observable<JsonResult>{
    let record:SysRolep = this.editCache[uuid].data;

    return this.saveOne(record).pipe(map(
      ( jr:JsonResult ) =>{

        if( jr.code !==1 ) return jr;

        let newData:SysRolep = jr.data;
        newData.uuid = UUID.UUID();
        
        this.tableData = this.arrUtils.replace<SysRolep>(this.tableData,rowIndex,newData);
        this.tableDataDisplay = this.arrUtils.replace<SysRolep>(this.tableData,rowIndex,newData);

        // 之前的方法不能兼容多行同时编辑
        // 多行都处于编辑状态时，保存一行，其他行都会恢复为编辑前数据和状态
        this.updateEditCacheOneRow(newData);

        return jr;
      }
    ))
  }
  //#endregion

  //#region 只更新当前保存的一行，兼容多行同时编辑
  updateEditCacheOneRow(data:SysRolep){
    this.editCache[data.uuid] = { edit:false,data:{...data} };
  }
  //#endregion

  //#region 删除一行数据
  deleteRow(rowIndex:number,uuid:string):Observable<JsonResult>{
    if( rowIndex === undefined || rowIndex === null || rowIndex<0 ) return of(new JsonResult);
    if( !uuid) return of(new JsonResult);
    let iid:number = this.tableDataDisplay[rowIndex].iid;
    if( !iid ) {
      this.updateStatistics();
      return of(new JsonResult);
    }

    return this.deleteByPrimaryKey(iid,rowIndex);
  }
  //#endregion

  //#region 前端删除行
  deleteRow_front(uuid:string){
    this.tableData = this.tableData.filter( item => item.uuid !==uuid );
    this.tableDataDisplay = this.tableDataDisplay.filter( item => item.uuid !==uuid );
    this.updateEditCacheWithTableData();
  }
  //#endregion

  //#region 前端作废一行数据
  nullifyRow_front(rowIndex:number,uuid:string){
    this.tableData[rowIndex].state = 0;
    this.tableDataDisplay[rowIndex].state = 0;
    this.editCache[uuid].data.state = 0;

    this.tableDataDisplay = this.tableDataDisplay.filter( item => 1===1 );
  }
  //#endregion

  //#region 设置对齐方式
  colHeaderAlign(fieldName:string):string{
    if( !this.tableStyle ) return;
    let tsRow:TableStyle = this.tableStyle.filter( item => item.field_name === fieldName )[0];
    return tsRow.align_header;
  }

  colContentAlign(fieldName:string):string{
    if( !this.tableStyle ) return;
    let tsRow:TableStyle = this.tableStyle.filter( item => item.field_name === fieldName )[0];
    return tsRow.align_cell;
  }
  //#endregion

  //#region 复制行
  copyRow(rowIndex:number,uuid:string){
    let newRow:SysRolep = {...this.tableData[rowIndex]};
    newRow.uuid = UUID.UUID();
    newRow.iid = 0;

    this.tableData = this.tableData.concat({...newRow});
    this.tableDataDisplay = this.tableData;
    this.updateEditCacheWithTableData();
  }
  //#endregion

  //#region 变形后显示
  convertRaw2Show(record:SysRolep,tsRow:TableStyle):string{
    switch(tsRow.field_name){
      case 'company_sid':
        // return record.company_name;
        return this.breadField.transRaw2Display(record,tsRow);
      default:
        return this.breadField.transRaw2Display(record,tsRow);
    }
  }
  //#endregion

  //#region 更新统计数据
  updateStatistics(){
    this.statistics = null;
    this.statistics = {};
    if( !this.tableStyle ) return; // 没有获取到样式表数据则不初始化统计数据
    this.tableStyle.forEach(ele => {
      if( ele.statistics ){
        this.statistics[ele.field_name] = { value:0,label:'0' };
      }
    });

    let staArray:TableStyle[] = this.tableStyle.filter( item => item.statistics );

    if( !this.tableData ) return;
    this.tableDataDisplay.forEach(eleData => {
      staArray.forEach(eleStyle => {
        let fieldName:string = eleStyle.field_name;
        let data:number = eleData[fieldName];
        
        data = data === undefined ? 0:data;
        data = data === null ? 0:data;

        // 被删除的数据（无效数据）不参与统计
        if( eleData['state'] ===0 )
          data = 0;
        let addResult:number = data + this.statistics[fieldName].value;

        this.statistics[fieldName] = { value: addResult,label: addResult.toFixed(eleStyle.digit)};

      });
    });
  }
  //#endregion

  //#region 开启编辑状态
  startEdit(uuid:string):string{
    if( this.editCache[uuid].data.state !==1 ){
      return '无效数据不可修改！';
    }
    this.editCache[uuid].edit = true;
    return '';
  }
  //#endregion

}


// Author：chanchaw
// Generator Version：1.0 - 2019年11月16日 16点46分
// This Model Created：Tue Feb 18 2020 14:01:54 GMT+0800 (中国标准时间)
// 记得导入UUID工具：import { UUID } from 'angular2-uuid';
export class SysRolep{
  iid:number;
  role_iid:number;
  object_iid:number;
  permission_view:boolean;
  permission_new:boolean;
  permission_update:boolean;
  permission_delete:boolean;
  permission_audit:boolean;
  permission_cancel:boolean;
  permission_print:boolean;
  permission_export:boolean;
  permission_money:boolean;
  create_time:Date;
  uuid:string;
  state:number;

  role_sid:string;
  module_sid:string;
  object_sid:string;

  constructor(){
    this.uuid = UUID.UUID();
  }
}